#ifndef BASEOBJECT_H
#define BASEOBJECT_H

#include "VisibleObject.h"
#include "BulletDynamics\Dynamics\btRigidBody.h"
#include "BaseAudio.h"
#include "SettingsManager.h"
#include "boost\enable_shared_from_this.hpp"

class Sensor;
typedef boost::shared_ptr<Sensor> SensorPtr;
enum SensorPosition;

enum CollisionType
{
	COL_NOTHING = 0,
	COL_CHAR = 1,
	COL_ENEMY = 2,
	COL_CORNER = 4,
	COL_LEVEL = 8,
	COL_GRAVITY = 16,
	COL_MISSLE = 32,
	COL_TRIGGER = 64
};

enum ShapeType
{
	SHAPE_SPHERE = 0,
	SHAPE_CAPSULE = 1,
	SHAPE_CYLINDER = 2,
	SHAPE_BOX = 3,
	SHAPE_CONVEX = 4,
	SHAPE_MESH = 5,
};

struct BulletData
{
	BulletData(const OStringPtr collisionMeshName = OStringPtr(new Ogre::String("")),
			   const OStringPtr collisionName = OStringPtr(new Ogre::String("")),
			   const short type = COL_LEVEL,
			   const short mask = COL_NOTHING,
			   const bool isGhost = false,
			   const btScalar mass = btScalar(0.0f),
			   const ShapeType shape = SHAPE_BOX,
			   const bool extraNode = false,
			   const btScalar restitution = btScalar(1.0f),
			   const btScalar friction = btScalar(1.0f),
			   const btScalar linDamp = btScalar(0.0f),
			   const btScalar angDamp = btScalar(0.0f),
			   const btScalar angularFactX = btScalar(1.0f),
			   const btScalar angularFactY = btScalar(1.0f),
			   const btScalar angularFactZ = btScalar(1.0f))
		: collisionMeshName(collisionMeshName), collisionName(collisionName), mass(mass), restitution(restitution), 
		  friction(friction), linDamp(linDamp), angDamp(angDamp), angularFactX(angularFactX), angularFactY(angularFactY), angularFactZ(angularFactZ), 
		  shape(shape), type(type), mask(mask), isGhost(isGhost), extraNode(extraNode) { }

	OStringPtr collisionMeshName;
	OStringPtr collisionName;
	//properties
	btScalar mass;
	btScalar restitution;
	btScalar friction;
	//damping
	btScalar linDamp;
	btScalar angDamp;
	//angular factor
	btScalar angularFactX;
	btScalar angularFactY;
	btScalar angularFactZ;
	// Type of the collision shape
	ShapeType shape;
	// Type of object
	short type;
	// Mask represents all types of object that can collide with this object
	short mask;
	// This makes possible to transform object in ogre separable
	bool extraNode;
	//Makes this object a Ghost that doesnt have a physical effect on other objects
	bool isGhost;
};

typedef boost::shared_ptr<BulletData> BulletDataPtr;
typedef boost::shared_ptr<btGeneric6DofConstraint> JointPtr;

class BaseObject : public VisibleObject, public boost::enable_shared_from_this<BaseObject>
{
public:
	BaseObject(std::string actorID);
	BaseObject(std::string actorID, std::string name, btVector3 &pos, btQuaternion &rot, btVector3 &scale, std::string mesh);
	BaseObject(boost::shared_ptr<SettingsManager> sm);
	BaseObject(const OgreDataPtr ogreData, const BulletDataPtr bulletData);
	BaseObject(boost::shared_ptr<BaseObject> ref);
	~BaseObject(void);
	const BulletDataPtr getBulletInitData(void) const;
	void setBody(btRigidBody *body);
	btRigidBody *getBody(void) const;
	void setNode(Ogre::SceneNode *node);
	Ogre::SceneNode *getNode(void) const;
	btScalar getVelAngle(void)const;
	void setVelAngle(btScalar angle);
	virtual void setSound(const SoundType type, const ALuint source);
	virtual const ALuint getSound(const SoundType type) const;
	virtual bool dead(void) const;
	virtual void kill(void);
	virtual void collision(boost::shared_ptr<BaseObject> obj, btVector3 &point);
	virtual void update(const unsigned long elapsedTime);
	virtual void scalePower(const char power);
	void addSensors(void);
	virtual void sensorCollision(boost::shared_ptr<BaseObject> obj, SensorPosition pos);
	bool isInAir(void);
	btVector3 getLocalVelocity(void);
	void setLocalVelocity(btVector3 &vel);
	btVector3 getLocalVector(const btVector3 &vec);
	btVector3 getGlobalVector(const btVector3 &vec);
	btVector3 physicsSize(void);
	JointPtr getJoint(void);
	void setJoint(JointPtr);
protected:
	void readBaseObjectFromXML(boost::shared_ptr<SettingsManager> sm);
	// This variable contains all data is needed for Bullet
	BulletDataPtr mpBulletInitData;
	btRigidBody *mpBody;
	Ogre::SceneNode *mpNode;
	btScalar mVelAngle;
	ALuint mIdleSound;
	bool hasSensors;
	SensorPtr left;
	SensorPtr right;
	SensorPtr top;
	SensorPtr bottom;
	JointPtr mpJoint;
};
typedef boost::shared_ptr<BaseObject> BaseObjectPtr;
typedef std::list<BaseObjectPtr> BaseObjectList;

#endif